﻿using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Xml.XPath;
using System.IO;

namespace ServBus.ListForm2010.Utility
{
    public class Manifest
    {
        private XmlDocument mXmlDoc;
        private XPathNavigator mNav;
        private string mName = "manifest.xsf";
        private string mPath;
        private InfoPathContext mContext;

        public Manifest(InfoPathContext context)
        {
            mXmlDoc = new XmlDocument();
            mContext = context;
            string temContent = File.ReadAllText(NameSpaceConstants.TemplateRootPath + "manifest.txt", Encoding.UTF8).Replace(NameSpaceConstants.XSDNamespaceValuePlaceHolder, mContext.XSDSchemaValue);
            temContent = temContent.Replace(NameSpaceConstants.SchemaTimePlaceHolder, mContext.Time);
            mXmlDoc.LoadXml(temContent);
            mNav = mXmlDoc.CreateNavigator();
            mPath = context.Path;
        }

        public void CreateTemplateManifest()
        {
            Save();

        }

        public void AddQueryObject()
        {
            string dsXml = "<xsf:query><xsf:sharepointListAdapterRW siteURL=\"" + mContext.CurrentSiteUrl + "\"" + " sharePointListID=\"" + "{"
                            + mContext.ListID + "}\" contentTypeID=\"" + mContext.ListContentTypeName + "\" relativeListUrl=\""
                            + mContext.MainListFullUrl + "\" queryAllowed=\"yes\" submitAllowed=\"yes\" name=\"" + mContext.ListName + "\" "
                            + NameSpaceConstants.XSFNameSpaceDefine + ">";

            StringBuilder strBuilder = new StringBuilder(dsXml);
            List<FieldInfo> fields = mContext.MainListFields;
            foreach (FieldInfo fld in fields)
            {
                string IdFld = "<xsf:field internalName=\"{0}\" type=\"{1}\" required=\"{2}\" appendOnly=\"no\" " + NameSpaceConstants.XSFNameSpaceDefine + "></xsf:field>";
                strBuilder.AppendFormat(IdFld, fld.Name, fld.Type.ToString(), fld.Required ? "yes" : "no");
            }
            strBuilder.Append("</xsf:sharepointListAdapterRW></xsf:query>");
            mNav.MoveToChild("xDocumentClass", NameSpaceConstants.XSFNameSpaceValue);
            XPathNavigator nav = XmlUtility.CreateDocNav(strBuilder.ToString());
            mNav.AppendChild(nav);
            Save();
        }

        private void Save()
        {
            string path = mPath + "\\" + mName;
            mXmlDoc.Save(path);
            if (!mContext.FilesToBeCleared.Contains(path))
            {
                mContext.FilesToBeCleared.Add(path);
            }
        }

        //public void AddDataObjectXsdFile(string fieldName, string dataObjName)
        //{
        //    mNav.MoveToRoot();
        //    mNav.MoveToChild("xDocumentClass", NameSpaceConstants.XSFNameSpaceValue);
        //    mNav.MoveToChild("package", NameSpaceConstants.XSFNameSpaceValue);
        //    mNav.MoveToChild("files", NameSpaceConstants.XSFNameSpaceValue);

        //    string x5 = string.Format("<xsf:file name=\"lookup1.xsd\" " + NameSpaceConstants.XSFNameSpaceDefine + " >"
        //              + "<xsf:fileProperties " + NameSpaceConstants.XSFNameSpaceDefine + ">"
        //              + "<xsf:property name=\"namespace\" type=\"string\" value=\"http://schemas.microsoft.com/office/infopath/2003/dataFormSolution\" " + NameSpaceConstants.XSFNameSpaceDefine + "></xsf:property>"
        //              + "<xsf:property name=\"dataObject\" type=\"string\" value=\"{0}\" " + NameSpaceConstants.XSFNameSpaceDefine + "></xsf:property>"
        //              + "<xsf:property name=\"rootElement\" type=\"string\" value=\"myFields\" " + NameSpaceConstants.XSFNameSpaceDefine + "></xsf:property>"
        //              + "<xsf:property name=\"useOnDemandAlgorithm\" type=\"string\" value=\"yes\" " + NameSpaceConstants.XSFNameSpaceDefine + "></xsf:property>"
        //              + "</xsf:fileProperties>"
        //              + "</xsf:file>", dataObjName);
        //    string x4 = string.Format("<xsf:file name=\"lookup1_qf.xsd\" " + NameSpaceConstants.XSFNameSpaceDefine + ">"
        //              + "<xsf:fileProperties " + NameSpaceConstants.XSFNameSpaceDefine + ">"
        //              + "<xsf:property name=\"namespace\" type=\"string\" value=\"http://schemas.microsoft.com/office/infopath/2009/WSSList/queryFields\" " + NameSpaceConstants.XSFNameSpaceDefine + "></xsf:property>"
        //              + "<xsf:property name=\"dataObject\" type=\"string\" value=\"{0}\" " + NameSpaceConstants.XSFNameSpaceDefine + "></xsf:property>"
        //              + "</xsf:fileProperties>"
        //              + "</xsf:file>", dataObjName);
        //    string x3 = string.Format("<xsf:file name=\"lookup1_df.xsd\" " + NameSpaceConstants.XSFNameSpaceDefine + ">"
        //              + "<xsf:fileProperties " + NameSpaceConstants.XSFNameSpaceDefine + ">"
        //              + "<xsf:property name=\"namespace\" type=\"string\" value=\"http://schemas.microsoft.com/office/infopath/2009/WSSList/dataFields\" " + NameSpaceConstants.XSFNameSpaceDefine + "></xsf:property>"
        //              + "<xsf:property name=\"dataObject\" type=\"string\" value=\"{0}\" " + NameSpaceConstants.XSFNameSpaceDefine + "></xsf:property>"
        //              + "</xsf:fileProperties>"
        //              + "</xsf:file>", dataObjName);
        //    string x2 = string.Format("<xsf:file name=\"lookup1_item_type.xsd\" " + NameSpaceConstants.XSFNameSpaceDefine + ">"
        //               + "<xsf:fileProperties " + NameSpaceConstants.XSFNameSpaceDefine + ">"
        //               + "<xsf:property name=\"namespace\" type=\"string\" value=\"http://schemas.microsoft.com/office/2009/documentManagement/types\" " + NameSpaceConstants.XSFNameSpaceDefine + "></xsf:property>"
        //               + "<xsf:property name=\"dataObject\" type=\"string\" value=\"{0}\" " + NameSpaceConstants.XSFNameSpaceDefine + "></xsf:property>"
        //               + "</xsf:fileProperties>"
        //               + "</xsf:file>", dataObjName);
        //    string x1 = string.Format("<xsf:file name=\"lookup1_item_controls.xsd\" " + NameSpaceConstants.XSFNameSpaceDefine + ">"
        //    + "<xsf:fileProperties " + NameSpaceConstants.XSFNameSpaceDefine + ">"
        //    + "<xsf:property name=\"namespace\" type=\"string\" value=\"http://schemas.microsoft.com/office/infopath/2007/PartnerControls\" " + NameSpaceConstants.XSFNameSpaceDefine + "></xsf:property>"
        //    + "<xsf:property name=\"dataObject\" type=\"string\" value=\"{0}\" " + NameSpaceConstants.XSFNameSpaceDefine + "></xsf:property>"
        //    + "</xsf:fileProperties>"
        //    + "</xsf:file>", dataObjName);


        //    List<string> lists = new List<string>();
        //    lists.Add(x5);
        //    lists.Add(x4);
        //    lists.Add(x3);
        //    lists.Add(x2);
        //    lists.Add(x1);

        //    foreach (string x in lists)
        //    {
        //        XPathNavigator mChildNav = XmlUtility.CreateDocNav(x);
        //        mChildNav.MoveToChild("file", NameSpaceConstants.XSFNameSpaceValue);
        //        mNav.AppendChild(mChildNav);
        //    }

        //    Save();
        //}
        /// <summary>
        /// add for publish.
        /// </summary>
        /// <param name="siteUrl"></param>
        /// <param name="path"></param>
        /// <param name="relativeBase"></param>
        /// <param name="ctName"></param>
        //public void AddExtensions(string site, string path, string ctName, string adminPath, string adminSite, string relativeUrl)
        //{
        //    string str = string.Format(NameSpaceConstants.Contants_Extensions, site, path, ctName, adminPath, adminSite, relativeUrl);
        //    mNav.MoveToChild("xDocumentClass", NameSpaceConstants.XSFNameSpaceValue);
        //    XPathNavigator nav = XmlUtility.CreateDocNav(str);
        //    mNav.AppendChild(nav);
        //    Save();
        //}

        public void AddExtensions(string site, string path, string ctName, string fullPath)
        {
            string str = string.Format(NameSpaceConstants.Contants_Extensions, site, path, ctName, fullPath);
            List<FieldInfo> fields = mContext.MainListFields;
            foreach (FieldInfo fld in fields)
            {
                if (fld.Required && fld.Type.Equals(FieldType.MultiText))
                {
                    str += "<xsf3:customValidation>";
                    str += " <xsf3:errorBlank match=\"/my:myFields/my:" + fld.Name + "\" expressionContext=\".\"";
                    str += " expression=\"(. = &quot;&quot; or . = &quot; &quot; or . = &quot;​&quot;) and not(descendant-or-self::node()/*[name() = &quot;img&quot;])\">";
                    str += "</xsf3:errorBlank></xsf3:customValidation>";
                }
            }
            str = str + NameSpaceConstants.Contants_Extensions_Complement;
            mNav.MoveToChild("xDocumentClass", NameSpaceConstants.XSFNameSpaceValue);
            XPathNavigator nav = XmlUtility.CreateDocNav(str);
            mNav.AppendChild(nav);
            Save();
        }

        public void AddXmlToEdit()
        {
            List<FieldInfo> fields = new List<FieldInfo>();
            fields.AddRange(mContext.MainListFields);
            if (mContext.SecondListInfos != null)
            {
                foreach (ListInfo sListInfo in mContext.SecondListInfos)
                {
                    fields.AddRange(sListInfo.Fields);
                }
            }
            XmlDocument xmlDoc = new XmlDocument();
            string path = mPath + mName;
            xmlDoc.Load(path);
            XPathNavigator nav = xmlDoc.CreateNavigator();
            XmlNamespaceManager mNameManager = new XmlNamespaceManager(nav.NameTable);
            mNameManager.AddNamespace("xsf", "http://schemas.microsoft.com/office/infopath/2003/solutionDefinition");
            mNameManager.AddNamespace("my", "http://schemas.microsoft.com/office/infopath/2003/myXSD/2011-06-30T11:22:21");
            XPathNodeIterator iter = mNav.Select("/xsf:xDocumentClass/xsf:views/xsf:view", mNameManager);
            StringBuilder xmlNodeStr = new StringBuilder();
            xmlNodeStr.Append("<xsf:editing>");
            if (iter.MoveNext())
            {
                foreach (FieldInfo fld in fields)
                {
                    switch (fld.Type)
                    {
                        case FieldType.MultiText:
                            //<xsf:xmlToEdit name="Test2_1" item="/dfs:myFields/dfs:dataFields/my:SharePointListItem_RW/my:Test2">
                            //<xsf:editWith type="rich" autoComplete="no" component="xField"></xsf:editWith></xsf:xmlToEdit>
                            if (fld.Required)
                            {
                                xmlNodeStr.AppendFormat("<xsf:editWith type=\"rich\"   autoComplete=\"no\" component=\"xField\"></xsf:editWith></xsf:xmlToEdit>");
                            }
                            else
                            {
                                xmlNodeStr.AppendFormat("<xsf:xmlToEdit name=\"{0}{1}_x1\" item=\"/my:myFields/my:{1}\">", fld.UniqueName, fld.Name);
                                xmlNodeStr.AppendFormat("<xsf:editWith type=\"rich\" autoComplete=\"no\" component=\"xField\"></xsf:editWith></xsf:xmlToEdit>");
                            }
                            break;
                        case FieldType.CheckBox:
                            //<xsf:xmlToEdit name="TestField3_x002d_3_1" item="/dfs:myFields/dfs:dataFields/my:SharePointListItem_RW/my:TestField3_x002d_3/Value">
                            //<xsf:editWith autoComplete="no" component="xTextList"></xsf:editWith>
                            xmlNodeStr.AppendFormat("<xsf:xmlToEdit name=\"{0}{1}_x1\" item=\"/my:myFields/my:{1}/my:{1}_1\">", fld.UniqueName, fld.Name);
                            xmlNodeStr.AppendFormat("<xsf:editWith autoComplete=\"no\" component=\"xTextList\"></xsf:editWith></xsf:xmlToEdit>");
                            break;
                        default:
                            break;
                    }
                }
            }

            //lookupform
            if (mContext.SecondListInfos != null)
            {
                //<xsf:xmlToEdit name="Announcements_72" item="/my:myFields/my:group1/my:Announcements" container="/my:myFields/my:group1">
                //    <xsf:editWith caption="Announcements" xd:autogeneration="template" component="xCollection">
                //        <xsf:fragmentToInsert>
                //            <xsf:chooseFragment innerFragment="my:Announcements">
                //                <my:Announcements>
                //                    <my:Title></my:Title>
                //                    <my:Body></my:Body>
                //                    <my:Expires xsi:nil="true"></my:Expires>

                //                </my:Announcements>
                //            </xsf:chooseFragment>
                //        </xsf:fragmentToInsert>
                //    </xsf:editWith>
                //</xsf:xmlToEdit>
                int count = 1;
                foreach (ListInfo sListInfo in mContext.SecondListInfos)
                {
                    xmlNodeStr.AppendFormat("<xsf:xmlToEdit name=\"{2}_72\" item=\"/my:myFields/my:SubForms/my:{0}/my:{1}\" container=\"/my:myFields\">", "List" + count, "ContentType" + count, (sListInfo.Name + sListInfo.CTypeName).Replace(" ", "_"));
                    xmlNodeStr.AppendFormat("<xsf:editWith caption=\"{0}\" xd:autogeneration=\"template\" component=\"xCollection\">", "List" + count);
                    xmlNodeStr.AppendFormat("<xsf:fragmentToInsert><xsf:chooseFragment innerFragment=\"my:SubForms/my:{0}/my:{1}\" ><my:SubForms><my:{0}><my:{1} my:ContentType_ID=\"{2}\">", "List" + count, "ContentType" + count, sListInfo.CTypeId);
                    foreach (FieldInfo sFieldInfo in sListInfo.Fields)
                    {
                        if (sFieldInfo.Name == "ID")
                        {
                            xmlNodeStr.AppendFormat("<my:{0}>1</my:{0}>", sFieldInfo.Name);
                        }
                        else
                        {
                            xmlNodeStr.AppendFormat("<my:{0}></my:{0}>", sFieldInfo.Name);
                        }
                    }
                    xmlNodeStr.AppendFormat("</my:{1}></my:{0}></my:SubForms></xsf:chooseFragment></xsf:fragmentToInsert></xsf:editWith></xsf:xmlToEdit>", "List" + count, "ContentType" + count);
                    count++;
                }
            }

            xmlNodeStr.Append("</xsf:editing>");

            iter.Current.AppendChild(xmlNodeStr.ToString());
            xmlDoc.LoadXml(mNav.OuterXml);
            xmlDoc.Save(path);

            //Add MenuArea            
            //<xsf:menuArea name="msoStructuralEditingContextMenu">
            //    <xsf:button action="xCollection::insertBefore" xmlToEdit="Announcements_72"
            //                caption="Insert Announcements before" showIf="immediate"></xsf:button>
            //    <xsf:button action="xCollection::insertAfter" xmlToEdit="Announcements_72"
            //                caption="Insert Announcements after" showIf="immediate"></xsf:button>
            //    <xsf:button action="xCollection::remove" xmlToEdit="Announcements_72" caption="Remove Announcements"
            //                showIf="immediate"></xsf:button>
            //    <xsf:button action="xCollection::insert" xmlToEdit="Announcements_72" caption="Insert Announcements"
            //                showIf="immediate"></xsf:button>
            //</xsf:menuArea>
            if (mContext.SecondListInfos != null)
            {
                foreach (ListInfo sListInfo in mContext.SecondListInfos)
                {
                    string str = "<xsf:button action=\"xCollection::insertBefore\" xmlToEdit=\"{0}_72\""
                                        + " caption=\"Insert {0} before\" showIf=\"immediate\"></xsf:button>"
                                    + "<xsf:button action=\"xCollection::insertAfter\" xmlToEdit=\"{0}_72\""
                                        + " caption=\"Insert {0} after\" showIf=\"immediate\"></xsf:button>"
                                    + "<xsf:button action=\"xCollection::remove\" xmlToEdit=\"{0}_72\""
                                        + " caption=\"Remove {0}\" showIf=\"immediate\"></xsf:button>"
                                    + "<xsf:button action=\"xCollection::insert\" xmlToEdit=\"{0}_72\""
                                        + " caption=\"Insert {0}\" showIf=\"immediate\"></xsf:button>";
                    string edirAreaStr = string.Format(str, (sListInfo.Name + sListInfo.CTypeName).Replace(" ", "_"));

                    //XPathNavigator childNav = XmlUtility.CreateDocNav(edirAreaStr);
                    XmlNamespaceManager manager = new XmlNamespaceManager(mNav.NameTable);
                    manager.AddNamespace("xsd", NameSpaceConstants.XSDNameSpaceValue);
                    manager.AddNamespace("xsf", NameSpaceConstants.XSFNameSpaceValue);
                    XPathNodeIterator childNavIter = mNav.Select(@"/xsf:xDocumentClass/xsf:views/xsf:view/xsf:menuArea", manager);
                    if (childNavIter.MoveNext())
                    {
                        childNavIter.Current.AppendChild(edirAreaStr);
                    }
                    else
                    {
                        childNavIter = mNav.Select(@"/xsf:xDocumentClass/xsf:views/xsf:view", manager);
                        edirAreaStr = "<xsf:menuArea name=\"msoStructuralEditingContextMenu\">" + edirAreaStr + "</xsf:menuArea>";
                        childNavIter.MoveNext();
                        childNavIter.Current.AppendChild(edirAreaStr);
                    }
                }
            }
            xmlDoc.LoadXml(mNav.OuterXml);
            xmlDoc.Save(path);
        }

        public void AddRepeatTableEditing(List<ListInfo> mListInfos)
        {
            //<xsf:editing>
            //    <xsf:xmlToEdit name="Contact_12" item="/my:myFields/my:Contact" container="/my:myFields">
            //        <xsf:editWith caption="Contact" xd:autogeneration="template" component="xCollection">
            //            <xsf:fragmentToInsert>
            //                <xsf:chooseFragment innerFragment="my:Contact">
            //                    <my:Contact>
            //                        <my:ContentType></my:ContentType>
            //                        <my:Title></my:Title>
            //                        <my:ClientName></my:ClientName>
            //                        <my:ID></my:ID>
            //                    </my:Contact>
            //                </xsf:chooseFragment>
            //            </xsf:fragmentToInsert>
            //        </xsf:editWith>
            //    </xsf:xmlToEdit>
            //</xsf:editing>
            //<xsf:menuArea name="msoStructuralEditingContextMenu">
            //    <xsf:button action="xCollection::insertBefore" xmlToEdit="Contact_12" caption="在前面插入 Contact" showIf="immediate"></xsf:button>
            //    <xsf:button action="xCollection::insertAfter" xmlToEdit="Contact_12" caption="在后面插入 Contact" showIf="immediate"></xsf:button>
            //    <xsf:button action="xCollection::remove" xmlToEdit="Contact_12" caption="删除 Contact" showIf="immediate"></xsf:button>
            //    <xsf:button action="xCollection::insert" xmlToEdit="Contact_12" caption="插入 Contact" showIf="immediate"></xsf:button>
            //</xsf:menuArea>
            XmlDocument xmlDoc = new XmlDocument();
            string path = mPath + mName;
            xmlDoc.Load(path);
            XPathNavigator nav = xmlDoc.CreateNavigator();
            XmlNamespaceManager mNameManager = new XmlNamespaceManager(nav.NameTable);
            mNameManager.AddNamespace("xsf", "http://schemas.microsoft.com/office/infopath/2003/solutionDefinition");
            XPathNodeIterator iter = mNav.Select("/xsf:xDocumentClass/xsf:views/xsf:view/xsf:editing", mNameManager);
            if (iter.MoveNext())
            {
                StringBuilder xmlNodeStr = new StringBuilder();
                foreach (ListInfo listInfo in mListInfos)
                {
                    xmlNodeStr.AppendFormat("<xsf:xmlToEdit name=\"{0}_12\" item=\"/my:myFields/my:{0}\" container=\"/my:myFields\">", listInfo.Name);
                    xmlNodeStr.AppendFormat("<xsf:editWith caption=\"{0}\" xd:autogeneration=\"template\" component=\"xCollection\">", listInfo.Name);
                    xmlNodeStr.AppendFormat("<xsf:fragmentToInsert><xsf:chooseFragment innerFragment=\"my:{0}\"><my:{0}>", listInfo.Name);
                    foreach (FieldInfo fldInfo in listInfo.Fields)
                    {
                        xmlNodeStr.AppendFormat("<my:{0}></my:{0}>", fldInfo.Name);
                    }
                    xmlNodeStr.AppendFormat("</my:{0}></xsf:chooseFragment></xsf:fragmentToInsert></xsf:editWith></xsf:xmlToEdit>", listInfo.Name);
                }

                iter.Current.AppendChild(xmlNodeStr.ToString());
                xmlDoc.LoadXml(mNav.OuterXml);
                xmlDoc.Save(path);
            }
        }
    }
}
